package address

import (
	"context"
	"encoding/json"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"

	"laundry-service/app/client/internal/svc"
	"laundry-service/app/client/internal/types"
	"laundry-service/entity"

	"github.com/zeromicro/go-zero/core/logx"
)

type CreateAddressLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewCreateAddressLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateAddressLogic {
	return &CreateAddressLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *CreateAddressLogic) CreateAddress(req *types.CreateAddressReq) (resp *types.CreateAddressResp, err error) {
	userId, _ := l.ctx.Value("userId").(json.Number).Int64()

	address := new(entity.Address)
	address.Region = req.Region
	address.Detail = req.Detail
	address.Phone = req.Phone
	address.Name = req.Name
	address.UserId = userId
	address.PostalCode = req.PostalCode
	address.Default = req.Default

	if err := l.verifyAddressAvailable(address); err != nil {
		return nil, err
	}

	if req.Default {
		if err := l.svcCtx.Db.ClearAddrPreDefault(userId); err != nil {
			return nil, err
		}
	}

	if err := l.svcCtx.Db.SaveAddr(address); err != nil {
		return nil, err
	}

	newAddress, err := l.svcCtx.Db.FindAddrById(userId, address.ID)
	if err != nil {
		return nil, err
	}

	resp = new(types.CreateAddressResp)
	resp.Region = newAddress.Region
	resp.Detail = newAddress.Detail
	resp.Phone = newAddress.Phone
	resp.Name = newAddress.Name
	resp.Id = newAddress.ID
	resp.PostalCode = newAddress.PostalCode
	resp.CreatedAt = newAddress.CreatedAt.Format("2006-01-02 15:04:05")
	resp.UpdatedAt = newAddress.UpdatedAt.Format("2006-01-02 15:04:05")
	resp.Default = newAddress.Default

	return resp, nil
}

// 请求无忧预下单接口
func (l *CreateAddressLogic) verifyAddressAvailable(address *entity.Address) error {
	requestUrl := fmt.Sprintf("%s/preOrder", l.svcCtx.Config.WY.BaseURL)

	senderContactInfo := newContactInfo(1, address)
	deliveryContactInfo := newContactInfo(2, address)
	reqBody := &entity.AddressXMLRep{
		ExpressType:  "2",
		ContactInfos: []entity.AddressXMLReqContactInfo{*senderContactInfo, *deliveryContactInfo},
	}

	xmlReqBody, err := xml.Marshal(reqBody)
	if err != nil {
		return err
	}

	formData := url.Values{}
	formData.Set("requestXml", string(xmlReqBody))
	formData.Set("aesEncode", "0")

	resp, err := http.Post(requestUrl, "application/x-www-form-urlencoded", strings.NewReader(formData.Encode()))
	if err != nil {
		return errors.New("请求地址验证接口失败")
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return errors.New("读取地址验证接口返回数据失败")
	}

	respBody := new(entity.AddressXMLResp)
	if err := xml.Unmarshal(body, &respBody); err != nil {
		return errors.New("解析地址验证接口返回数据失败")
	}

	if respBody.Head != "OK" {
		return errors.New(respBody.ErrMsg)
	} else {
		return nil
	}
}

func newContactInfo(contactType int, addr *entity.Address) *entity.AddressXMLReqContactInfo {
	regionArr := strings.Split(addr.Region, ",")

	return &entity.AddressXMLReqContactInfo{
		ContactType: contactType,
		Tel:         addr.Phone,
		Province:    regionArr[0],
		City:        regionArr[1],
		County:      regionArr[2],
		Address:     addr.Detail,
	}
}
